﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.Reflection;
using Krile.Kernel.Data;
using Krile.Kernel.Bridges;

namespace Krile.Cores.KeyAssignElems
{
    public class KeyAssignData
    {
        public Keys LinkedKeys { get; set; }

        public bool EnableOnTextBox { get; set; }

        [XmlElement("Method")]
        public KeyAssignMethodData[] InvokeMethodDatas { get; set; }

        public void DefreezeAll()
        {
            if (InvokeMethodDatas == null)
                return;
            foreach (var mtd in InvokeMethodDatas)
            {
                mtd.Defreeze();
                if (!mtd.IsAlive)
                    Subsystem.Debugger.AddReport("Method:" + mtd.TargetMethodName + " in " + mtd.TargetInstanceType + " is not found.");
            }
        }

        public void InvokeAll(IForm form, Status curStatus, Keys pressed)
        {
            if (InvokeMethodDatas == null)
                return;
            foreach (var mtd in InvokeMethodDatas)
            {
                mtd.Invoke(form, curStatus, pressed);
            }
        }

        public KeyAssignData() { }
    }

    public class KeyAssignMethodData
    {
        [XmlIgnore()]
        KeyAssignCallbackCandidate callbackMethod;

        string ___targetInstanceType;
        public string TargetInstanceType
        {
            get
            {
                if (callbackMethod != null && callbackMethod.CallbackMethod.Target != null)
                    return callbackMethod.CallbackMethod.Target.GetType().FullName;
                else
                    return ___targetInstanceType;
            }

            set
            {
                ___targetInstanceType = value;
            }
        }

        string ___targetMethodName;
        public string TargetMethodName
        {
            get
            {
                if (callbackMethod != null)
                    return callbackMethod.CallbackMethod.Method.Name;
                else
                    return ___targetMethodName;
            }
            set
            {
                ___targetMethodName = value;
            }
        }

        public bool IsAlive
        {
            get { return callbackMethod != null; }
        }

        public void Defreeze()
        {
            callbackMethod = Core.KeyAssign.LookupCallback(___targetInstanceType, ___targetMethodName);
        }

        public KeyAssignMethodData()
        {
            callbackMethod = null;
        }

        public KeyAssignMethodData(KeyAssignCallbackCandidate cand)
        {
            callbackMethod = cand;
        }

        public string Description
        {
            get
            {
                //NULLなら解凍を試みる
                if (callbackMethod == null)
                    Defreeze();

                if (callbackMethod != null)
                    return callbackMethod.Description;
                else
                    return "<Method not found. Target:" + TargetMethodName + " on " + TargetInstanceType + ">";
            }
        }

        public void Invoke(IForm form, Status curStatus, Keys pressed)
        {
            //NULLなら解凍を試みる
            if (callbackMethod == null)
                Defreeze();
            if (callbackMethod != null)
                callbackMethod.CallbackMethod.Invoke(form, curStatus, pressed);
        }
    }

    public class KeyAssignCallbackCandidate
    {
        public string Description;
        public Krile.Kernel.Data.Common.KeyAssignCallback CallbackMethod;

        public KeyAssignCallbackCandidate() { }
        public KeyAssignCallbackCandidate(Krile.Kernel.Data.Common.KeyAssignCallback callback, string desc)
        {
            Description = desc;
            if (callback == null)
                throw new ArgumentNullException("callback");
            CallbackMethod = callback;
        }

        public override string ToString()
        {
            int p = Description.IndexOf(":");
            if (p > 0)
                return Description.Substring(p + 1);
            else
                return Description;
        }
    }
}